﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint.Administration;
using Microsoft.SharePoint.Administration.Health;
using SDS.SPHealthAnalyzerRules.Delegation.Helpers;

namespace SDS.SPHealthAnalyzerRules.Delegation.Rules
{
    /// <summary>
    /// ensures that any Kerberos sites are configured to use a service account configured for delegation
    /// </summary>
    public class WebAppAppPools_Using_Delegation : SPHealthAnalysisRule
    {
        private Guid CorrelationToken = Guid.NewGuid();
        [System.Diagnostics.DebuggerDisplay("{WebAppName} using account {AppPoolAccount}")]
        private struct Error
        {
            public string WebAppName;
            public string AppPoolAccount;
        }
        readonly private List<Error> Errors = new List<Error>();
        readonly List<string> Remedies = new List<string>();

        public override SPHealthCategory Category { get { return SPHealthCategory.Configuration; } }
        public override SPHealthCheckErrorLevel ErrorLevel { get { return SPHealthCheckErrorLevel.Error; } }

        public override SPHealthAnalysisRuleAutomaticExecutionParameters AutomaticExecutionParameters
        {
            get
            {
                return new SPHealthAnalysisRuleAutomaticExecutionParameters()
                {
                    Schedule = SPHealthCheckSchedule.Daily,
                    Scope = SPHealthCheckScope.All,
                    ServiceType = typeof(SPWebService),
                    RepairAutomatically = false
                };
            }
        }

        public override SPHealthCheckStatus Check()
        {
            var outval = SPHealthCheckStatus.Failed;

            LoggingService.Write(LoggingService.Category_WebApp, TraceSeverity.Verbose, "Executing Health Check", CorrelationToken);

            Microsoft.SharePoint.SPSecurity.RunWithElevatedPrivileges(delegate { doCheck(); });

            // set return value
            outval = Errors.Count == 0
                 ? SPHealthCheckStatus.Passed
                 : SPHealthCheckStatus.Failed;

            LoggingService.Write(
                LoggingService.Category_WebApp,
                TraceSeverity.Verbose,
                String.Format("Health Check completed with outcome {0}", outval.ToString()),
                CorrelationToken);

            return outval;
        } // void Check()

        public override string Summary { get { return "DELEGATION: Web Application accounts not configured for delegation."; } }
        public override string Explanation
        {
            get
            {
                var x = Errors.Select(e => String.Format(@"WebApp [{0}] using account [{1}]",
                                                          e.WebAppName,
                                                          e.AppPoolAccount))
                              .ToArray();
                return String.Format(
                    @"{0}Web Applications which are configured for Kerberos Authentication must be hosted by a service account configured for delegation " +
                    @"{0}" +
                    @"{0}The following errors were found:" +
                    @"{0}{1}",

                    Environment.NewLine,
                    String.Join(Environment.NewLine, x)
                    ).Trim();
            }
        }
        public override string Remedy { get { return String.Format("Configure the web application accounts to allow delegation."); } }







        private void doCheck()
        {
            try
            {

                // if current server is running SPWebService (web apps)
                var Server = Microsoft.SharePoint.Administration.SPServer.Local;
                if (Server.isRunning<SPWebService>())
                {
                    // looking for webapps using kerberos
                    Server.WebApplications()
                          .UsingKerberos()
                          .Select(wa => new { WebApp = wa, AppPoolAccount = wa.ApplicationPool.Username.Split('\\').Last() })
                          .Where(x => Helpers.AD_Delegation.UserExists(x.AppPoolAccount))  // only applicable to domain accounts
                          .Where(x => Helpers.AD_Delegation.GetUser(x.AppPoolAccount).Permission == AD_Delegation.DelegationPermission.NoDelegation)
                          .ToList()
                          .ForEach(x =>
                          {
                              Errors.Add(new Error()
                              {
                                  WebAppName = x.WebApp.DisplayName,
                                  AppPoolAccount = x.AppPoolAccount
                              });
                          });
                } // local server is running SPWebService

            } // try
            catch (Exception ex)
            {
                LoggingService.Write(
                    LoggingService.Category_WebApp,
                    TraceSeverity.High,
                    String.Format("Health Check encountered the following exception: {0}", ex.Message),
                    CorrelationToken);
            }

        } // doCheck()


    } // class
} // namespace
